package com.flying.str;

import org.junit.Test;

/**
 * @ClassName: StringBulider
 * @author: 刘鹏飞
 * @date 2023/7/24 9:25
 * @Description: StringBulider的使用
 * <p>
 * 有一个和 StringBulider功能相似的类 StringBUffer
 * 区别在于 StringBulider是线程不安全,StringBuffer是线程安全的
 * 通常情况下推荐使用 StringBulider,效率高
 */
public class SBDemo {

    /*

 String /StringBuffer/StringBuilder的异同
 String:   不可变的字符序列; 底层使用char数组存储,JDK9改为byte数组
 StringBuffer: 可变的字符序列;   线程安全的,效率低
 StringBuilder : 可变的字符序列; JDK5.0新增的,线程不安全,效率高;


 源码分析:

 String str=new String();           //   new char[0]
 String str=new String("abc);       //   new char[]{'a','b','c'}

 StringBuffer sb1=new StringBuffer();   //  char[]  value = new char[16];   //  底层创建了一个长度为16的数组
 sb1.append('a') ;   //  value[0]='a';
 sb1.append('b') ;   //  value[1]='b';

 StringBuffer sb2=new StringBuffer("abc"); //  char[] value = new char["abc".length()+16]

//  问题一. System.out.println(sb2.length());   //  3

//  问题二:  扩容问题:如果添加的数据底层数组盛不下了,那就需要扩容底层的数组
            默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中

（1）StringBuffer append(xx)：提供了很多的append()方法，用于进行字符串追加的方式拼接
（2）StringBuffer delete(int start, int end)：删除[start,end)之间字符
（3）StringBuffer deleteCharAt(int index)：删除[index]位置字符
（4）StringBuffer replace(int start, int end, String str)：替换[start,end)范围的字符序列为str
（5）void setCharAt(int index, char c)：替换[index]位置字符
（6）char charAt(int index)：查找指定index位置上的字符
（7）StringBuffer insert(int index, xx)：在[index]位置插入xx
（8）int length()：返回存储的字符数据的长度
（9）StringBuffer reverse()：反转

*/


    @Test
    public void test0(){
        //
        String s = "hel";


        //  可变的字符串
        //  内部有一个没有被final修饰的数组 value,他的长度大于字符串的长度
        StringBuilder sb1 = new StringBuilder(s);

        sb1.append("123");
        sb1.append("12345465");
        sb1.append(43);
        sb1.append(new char[]{'+','-',111,'*','/','&','^','%',},2,4);
        System.out.println("sb1= "+sb1);


        // 将可变的字符串,转成不可变的字符串
        String s1 = sb1.toString();

        StringBuffer sb2 = new StringBuffer();

    }
    @Test
    public void test1() {
        StringBuffer sb1=new StringBuffer("abc");
        StringBuilder sb2=new StringBuilder("abc");
        String s=sb1.toString();

        sb2.setCharAt(1,'B');
        System.out.println("sb2 = " + sb2);

        // 方法链调用,这样的方法通常都是将当前对象作为返回值返回的
        sb2.append('d')
                .append(new char[]{'d','e','f'}) // 在可变字符串最后追加
                .replace(2,3,"你好世界");
        System.out.println("sb2 = " + sb2);

        sb2.reverse();
        System.out.println("sb2 = " + sb2);  // 反转


    }


    @Test
    public void test2() {
        StringBuilder sBuilder = new StringBuilder("Hello");
        sBuilder.insert(2, 1);  // 插入数字
        sBuilder.insert(2, "abc");

        System.out.println(sBuilder);
        StringBuilder reverse = sBuilder.reverse();
        System.out.println(reverse == sBuilder);


        System.out.println(sBuilder.length());   //  实际存储字符个数
    }


    /*
（1）int indexOf(String str)：在当前字符序列中查询str的第一次出现下标
（2）int indexOf(String str, int fromIndex)：在当前字符序列[fromIndex,最后]中查询str的第一次出现下标
（3）int lastIndexOf(String str)：在当前字符序列中查询str的最后一次出现下标
（4）int lastIndexOf(String str, int fromIndex)：在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标
（5）String substring(int start)：截取当前字符序列[start,最后]
（6）String substring(int start, int end)：截取当前字符序列[start,end)
（7）String toString()：返回此序列中数据的字符串表示形式
（8）void setLength(int newLength) ：设置当前字符序列长度为newLength
    */
    @Test
    public void test3() {
        StringBuilder sBuilder = new StringBuilder("abc");

        sBuilder.setLength(2);

        System.out.println(sBuilder);  // ab ,会根据新字符序列的长度删减字符

        sBuilder.setLength(100);
        System.out.println(sBuilder.charAt(99)==0);  // 空字符
        System.out.println("sBuilder = " + sBuilder); // "ab          "


    }




    /*
     测试String / StringBuffer / StringBuilder在操作数据方面的效率
    */
    @Test
    public void test4() {
        String str="";
        long l1 = Runtime.getRuntime().freeMemory();   //获取系统剩余内存
        long time1 = System.currentTimeMillis();       // 获取系统的当前时间

        for (int i = 0; i < 50000; i++) {  // 切记在工作中,不要写以下代码,会导致服务器宕机
            str+=i;  // 相当于创建了5000个对象
        }

        long l2 = Runtime.getRuntime().freeMemory();   //获取系统剩余内存
        long time2 = System.currentTimeMillis();       // 获取系统的当前时间

        System.out.println("String占用内存 "+(l2-l1));
        System.out.println("String占用时间"+(time2-time1));


        System.out.println("=============================================");
        StringBuilder str1=new StringBuilder();
        long l3 = Runtime.getRuntime().freeMemory();   //获取系统剩余内存
        long time3 = System.currentTimeMillis();       // 获取系统的当前时间

        for (int i = 0; i < 50000; i++) {
            str1.append(i);
        }

        long l4 = Runtime.getRuntime().freeMemory();   //获取系统剩余内存
        long time4 = System.currentTimeMillis();       // 获取系统的当前时间

        System.out.println("StringBuilder占用内存 "+(l4-l3));
        System.out.println("StringBuilder占用时间"+(time4-time3));





    }
}
